home *** CD-ROM | disk | FTP | other *** search
- //• Most procedures in this file were created by Tony Small, author
- //• of Cellusoft games. You may feel free to pass this code along
- //• to whom ever you like and look through the code and learn from it at
- //• your leisure.
-
- //• If, however, you choose to use any of the code below in one of
- //• your programs, you are first obligated to pay the standard
- //• shareware fee of $15. Upon payment of the fee, you may use any
- //• of the following procedures or the unit as a whole as many times
- //• as you choose in as many projects that you choose. It would
- //• also be appreciated if you mention Tony Small in the credits of
- //• any program you use his procedures in.
-
- //• Those who pay the shareware fee of $15 will also be informed of
- //• future Cellusoft games and future Cellusoft programming routines.
- //• Registered users will also be able to beta test all future
- //• Cellusoft games and be named in the credits when appropriate.
-
- //• In order to register, please send $15 to:
- //• Tony Small
- //• 18606 Cassandra St.
- //• Tarzana, CA 91356
-
- //• CellusoftAnimations© 1993 Tony Small - All Rights Reserved
- //• WorldWide
-
- //• ***Note*** - to use these routines, you don't necessarily have
- //• to understand them. Simply read through the explanations in the
- //• interface section below and examine how they are used in the
- //• program sample file.
-
- //• Questions? Send mail or E-mail AOL - TonyS33
-
- //• This file was translated to C by Matt Burch - Singularity
- //• Software. Also, all offscreen port routines were created from
- //• modified Principia routines by Matt Burch. This translation is
- //• BetaWare - don’t forget to send Tony his registration fee, but
- //• it’d also be appreciated if you’d make Matt Burch a beta tester
- //• for your game. You can contact him at:
-
- //• AOL: Black Mac
- //• Internet: blackmac@aol.com
- //• US Mail: Matt Burch
- //• 2261 Roach St.
- //• Salina, KS 67401
-
- //• Stay tuned for more great code from Cellusoft and Singularity.
- //• Also, be sure not to miss "Rapier: XF7500,"
- //• coming in summer ’93 from Singularity!
-
-
- #pragma once
- #include "Cellusoft.h"
- #include "GestaltEqu.h"
-
- //• Maximum number of bytes in a row of pixels.
- #define kMaxRowBytes 0x3FFE
-
- //• Default resolution is 72 DPI; Fixed type.
- #define kDefaultRes 0x00480000
- #define kITabRes 4 //• Inverse-table resolution.
-
- //• The following functions help to manage the actual animation process.
- //• Call InitAnimations after every animation loop.
- //• InitAnimations will reset the animArray to its original state.
- //• Call SetAnimation to add an animation to the array. tlRect specifies
- //• where the animated graphic was last on the screne.
- //• tcRect specifies where the animated graphic is now on the screne.
- //• tpRect specifies the location of the graphic on the GrafPtr where the
- //• actual picture to be animated is located.
- //• ttheGraf is the port that holds that picture and tthemaskGraf is the
- //• port with the mask of that picture.
- //• AnimateArray will animate all of the animations you specified with each
- //• SetAnimation call. The maximum number of animations there can be at
- //• the same time is only limited by the constant MaxAnimations. This
- //• procedure also handled the collisions of any number of animations
- //• without flicker.
- //• pureback is the port that holds the original picture of the background
- //• graphic.
- //• offLoad is a blank port the same size of the MainWindow.
- //• MainWindow is the pointer to the window where the user will see the
- //• animations take place.
- //• ***Note*** - The method of animation used was developed by John Calhoun,
- //• author of Glider 4.0. If you would like to learn more about the flicker
- //• free technique used by his programs and by these routines, then look
- //• for either Glypha 2.0 source code or Glypha Primer offered by John
- //• Calhoun available on AOL and other bulletin boards.
-
- //• The following two functions are simply easier ways to call
- //• sometimes complicated system routines.
- //• Copy replaces CopyBits. With this, you do not need to put
- //• in ^.portbits and specify the regionhandle and other odd variables.
- //• This simply copies from Port1 to Port2, from Rect1 to Rect2.
- //• MoveRect moves TheRect, the specified integers. MoveRect is
- //• used by other CellusoftAnimations routines.*/
-
- void Copy (GrafPtr Port1, GrafPtr Port2, Rect Rect1, Rect Rect2)
- {
- CopyBits (& ((GrafPtr)Port1)->portBits, & ((GrafPtr)Port2)->portBits, &Rect1, &Rect2, 0, theregion);
- }
-
- void AnimateArray (GrafPtr pureback, GrafPtr offLoad, WindowPtr mainWindow)
- {
- int i, j;
- Rect wRect[MaxAnimations+1];
- Boolean col[MaxAnimations+1];
-
- for (i = 1; i <= MaxAnimations; i++)
- if (animArray[i].active)
- UnionRect (&animArray[i].lRect,
- &animArray[i].cRect,
- &wRect[i]);
-
- for (i = 1; i <= MaxAnimations; i++)
- {
- if (animArray [i].active)
- {
- for (j = i + 1; j <= MaxAnimations; j++)
- col[j] = FALSE;
- tr [2] = wRect[i];
- for (j = i + 1; j <= MaxAnimations; j++)
- {
- if (animArray[j].active)
- if (SectRect (&tr[2], &wRect[j], &tr[1]))
- {
- col[j]=TRUE;
- animArray[j].active=false;
- UnionRect (&tr[2], &wRect[j], &tr[2]);
- }
- }
- col[i]=TRUE;
- Copy (pureback, offLoad, tr[2], tr[2]);
-
- for (j = i; j <= MaxAnimations; j++)
- {
- if (col[j])
- {
- CopyMask (& ((GrafPtr)animArray[j].theGraf)->portBits,
- & ((GrafPtr)animArray[j].theMaskGraf)->portBits,
- & ((GrafPtr)offLoad)->portBits,
- &animArray[j].pRect,
- &animArray[j].pRect,
- &animArray[j].cRect);
- }
- }
-
- Copy (offLoad, mainWindow, tr[2], tr[2]);
- }
- }
- }
-
- void SetAnimation (Rect tlRect, Rect tcRect, Rect tpRect, GrafPtr ttheGraf, GrafPtr tthemaskGraf)
- {
- int i;
-
- i = 1;
- while ((animArray[i].active) && (i < MaxAnimations))
- i++;
-
- animArray[i].active = TRUE;
- animArray[i].lRect = tlRect;
- animArray[i].cRect = tcRect;
- animArray[i].pRect = tpRect;
- animArray[i].theGraf = ttheGraf;
- animArray[i].theMaskGraf = tthemaskGraf;
- }
-
-
- void InitAnimations ()
- {
- int i;
-
- for (i = 1; i <= MaxAnimations; i++)
- animArray[i].active = FALSE;
- }
-
- void MoveRect (Rect *TheRect, int left, int up, int right, int down)
- {
- TheRect->left = TheRect->left + left;
- TheRect->top = TheRect->top + up;
- TheRect->right = TheRect->right + right;
- TheRect->bottom = TheRect->bottom + down;
- }
-
- DoAlert (Str255 a) //• yell at the user
- {
- ParamText (a, "\p", "\p", "\p");
- StopAlert (128, nil);
- }
-
- //• SetUpPixMap and CreateGDevice are used internally by the Cellusoft
- //• routines ONLY. Your application shouldn’t have any reason to call these.
-
- OSErr SetUpPixMap (short depth, Rect *bounds, CTabHandle colors, short bytesPerRow, PixMapHandle aPixMap)
- {
- CTabHandle newColors; //• Color table used for the off-screen PixMap.
- Ptr offBaseAddr; //• Pointer to the off-screen pixel image.
- OSErr error; //• Returns error code.
-
- error = noErr;
- newColors = nil;
- offBaseAddr = nil;
-
- //• Clone the clut if indexed color; allocate a dummy clut if direct color.
- if (depth <= 8)
- {
- newColors = colors;
- error = HandToHand ((Handle *)&newColors);
- }
- else
- {
- newColors = (CTabHandle)NewHandle (sizeof (ColorTable) -
- sizeof (CSpecArray));
- error = MemError ();
- }
- if (error == noErr)
- {
- //• Allocate pixel image; long integer multiplication avoids overflow.
- offBaseAddr = NewPtr ((unsigned long)bytesPerRow * (bounds->bottom -
- bounds->top));
- if (offBaseAddr != nil)
- {
- //• Initialize fields common to indexed and direct PixMaps.
- (**aPixMap).baseAddr = offBaseAddr; //• Point to image.
- (**aPixMap).rowBytes = bytesPerRow | //• MSB set for PixMap.
- 0x8000;
- (**aPixMap).bounds = *bounds; //• Use given bounds.
- (**aPixMap).pmVersion = 0; //• No special stuff.
- (**aPixMap).packType = 0; //• Default PICT pack.
- (**aPixMap).packSize = 0; //• Always zero in mem.
- (**aPixMap).hRes = kDefaultRes; //• 72 DPI default res.
- (**aPixMap).vRes = kDefaultRes; //• 72 DPI default res.
- (**aPixMap).pixelSize = depth; //• Set # bits/pixel.
- (**aPixMap).planeBytes = 0; //• Not used.
- (**aPixMap).pmReserved = 0; //• Not used.
-
- //• Initialize fields specific to indexed and direct PixMaps.
- if (depth <= 8)
- {
- //• PixMap is indexed.
- (**aPixMap).pixelType = 0; //• Indicates indexed.
- (**aPixMap).cmpCount = 1; //• Have 1 component.
- (**aPixMap).cmpSize = depth; //• Component size=depth.
- (**aPixMap).pmTable = newColors; //• Handle to CLUT.
- }
- else
- {
- //• PixMap is direct.
- (**aPixMap).pixelType = RGBDirect; //• Indicates direct.
- (**aPixMap).cmpCount = 3; //• Have 3 components.
- if (depth == 16)
- (**aPixMap).cmpSize = 5; //• 5 bits/component.
- else
- (**aPixMap).cmpSize = 8; //• 8 bits/component.
- (**newColors).ctSeed = 3 * (**aPixMap).cmpSize;
- (**newColors).ctFlags = 0;
- (**newColors).ctSize = 0;
- (**aPixMap).pmTable = newColors;
- }
- }
- else
- error = MemError ();
- }
- else
- newColors = nil;
-
- //• If no errors occurred, return a handle to the new off-screen PixMap.
- if (error != noErr)
- {
- if (newColors != nil)
- DisposCTable (newColors);
- }
-
- //• Return the error code.
- return error;
- }
-
- //• CreateOffScreen takes a CGrafPtr and makes an offscreen port out of it.
- //• The first two parameters are the width and heighth (in pixels) of the
- //• port you want created.
- //• The third parameter is the pixel depth of the port. Pass it at 1 for
- //• a black and white port, an 8 for a 256-color port, etc. If you pass it
- //• a 0, it will use the current bit depth of the screen, which is useful
- //• if you want your program to be adaptable to different screens.
- //• The fourth parameter is a pointer to your new port. It normally takes a
- //• CGrafPtr, but you can also use it to dispose of a regular GrafPtr by
- //• using a (CGrafPtr) typecast. Example call:
- //• CreateOffScreen (300, 300, 8, & (CGrafPtr)myGrafPtr, 400);
- //• The last argument is the ID number of a pict, if you want to place one
- //• in your port. If you desire a blank port, just pass a -1 instead.
-
- OSErr CreateOffScreen (
- int right,
- int bottom,
- short depth,
- CGrafPtr *retPort,
- int picID)
- {
- CGrafPtr newPort; //• Pointer to the new off-screen CGrafPort.
- PixMapHandle newPixMap; //• Handle to the new off-screen PixMap.
- GDHandle newDevice; //• Handle to the new off-screen GDevice.
- long qdVersion; //• Version of QuickDraw currently in use.
- GrafPtr savedPort; //• Pointer to GrafPort used for save/restore.
- SignedByte savedState; //• Saved state of color table handle.
- short bytesPerRow; //• Number of bytes per row in the PixMap.
- OSErr error; //• Returns error code.
- CTabHandle colors;
- Rect bounds;
- PicHandle pic;
-
-
- if (depth==0)
- depth = (** ((**GetMainDevice ()).gdPMap)).pixelSize;
-
- colors = GetCTable (depth);
- SetRect (&bounds, 0, 0, right, bottom);
-
- //• Initialize a few things before we begin.
- newPort = nil;
- newPixMap = nil;
- newDevice = nil;
- error = noErr;
-
- //• Save the color table’s current state and make sure it isn’t purgeable.
- if (colors != nil)
- {
- savedState = HGetState ((Handle)colors);
- HNoPurge ((Handle)colors);
- }
-
- //• Calculate the number of bytes per row in the off-screen PixMap.
- bytesPerRow = ((depth * (bounds.right - bounds.left) + 31) >> 5) << 2;
-
- //• Get the current QuickDraw version.
- (void)Gestalt (gestaltQuickdrawVersion, &qdVersion);
-
- //• Make sure depth is indexed or depth is direct and 32-Bit QD installed.
- if (depth == 1 || depth == 2 || depth == 4 || depth == 8 ||
- ((depth == 16 || depth == 32) && qdVersion >= gestalt32BitQD))
- {
- //• Maximum number of bytes per row is 16,382; make sure within range.
- if (bytesPerRow <= kMaxRowBytes)
- {
- //• Make sure a color table is provided if the depth is indexed.
- if (depth <= 8)
- if (colors == nil)
- //• Indexed depth and clut is NIL; is parameter error.
- error = paramErr;
- }
- else
- //• # of bytes per row is more than 16,382; is parameter error.
- error = paramErr;
- }
- else
- //• Pixel depth isn’t valid; is parameter error.
- error = paramErr;
-
- //• If sanity checks succeed, then allocate a new CGrafPort.
- if (error == noErr)
- {
- newPort = (CGrafPtr)NewPtr (sizeof (CGrafPort));
- if (newPort != nil)
- {
- //• Save the current port.
- GetPort (&savedPort);
-
- //• Initialize the new CGrafPort and make it the current port.
- OpenCPort (newPort);
-
- //• Set portRect, visRgn, and clipRgn to the given bounds rect.
- newPort->portRect = bounds;
- RectRgn (newPort->visRgn, &bounds);
- ClipRect (&bounds);
-
- //• Initialize the new PixMap for off-screen drawing.
- error = SetUpPixMap (depth, &bounds, colors, bytesPerRow,
- newPort->portPixMap);
- if (error == noErr)
- {
- //• Grab the initialized PixMap handle.
- newPixMap = newPort->portPixMap;
-
- //• Allocate and initialize a new GDevice.
- error = CreateGDevice (newPixMap, &newDevice);
- }
-
- EraseRect (&bounds);
-
- if (picID!=-1)
- {
- pic=GetPicture (picID);
- if (pic!=nil)
- DrawPicture (pic, &bounds);
-
- }
-
- //• Restore the saved port.
- SetPort (savedPort);
- }
- else
- error = MemError ();
- }
-
- //• Restore the given state of the color table.
- if (colors != nil)
- HSetState ((Handle)colors, savedState);
-
- //• One Last Look Around The House Before We Go….
- if (error != noErr)
- {
- //• Some error occurred; dispose of everything we allocated.
- if (newPixMap != nil)
- {
- DisposCTable ((**newPixMap).pmTable);
- DisposPtr ((**newPixMap).baseAddr);
- }
- if (newDevice != nil)
- {
- DisposHandle ((Handle) (**newDevice).gdITable);
- DisposHandle ((Handle)newDevice);
- }
- if (newPort != nil)
- {
- CloseCPort (newPort);
- DisposPtr ((Ptr)newPort);
- }
- }
- else
- {
- //• Everything’s OK; return refs to off-screen CGrafPort and GDevice.
- *retPort = newPort;
- // *retGDevice = newDevice;
- }
- return error;
- }
-
- //• This function will take the GrafPtr Origin, and create a port of
- //• identical size called Destination and effectively perform a
- //• horizontal swap of the picture on Origin. This procedure is good
- //• to use if you want to save disk space by not having to put
- //• horizontally swapped pictures into the resource. Set the
- //• variable Color to true if the GrafPtr is a color port.
-
- void HorizontalFlip (GrafPtr *Origin, GrafPtr *Destination, Boolean Color)
- {
- int i;
- CGrafPtr tempPort;
-
- tr[1] = ((GrafPtr)Origin)->portRect;
- tempPort = (CGrafPtr)*Destination;
- if (Color)
- CreateOffScreen (tr[1].right, tr[1].bottom, 0, &tempPort, -1);
- else
- CreateOffScreen (tr[1].right, tr[1].bottom, 1, &tempPort, -1);
- *Destination= (GrafPtr)tempPort;
- SetRect (&tr[2], 0, 0, 1, tr[1].bottom);
- SetRect (&tr[3], tr[1].right - 1, 0, tr[1].right, tr[1].bottom);
- for (i = 1; i <= tr[1].right; i++)
- {
- Copy (*Origin, *Destination, tr[2], tr[3]);
- MoveRect (&tr[2], 1, 0, 1, 0);
- MoveRect (&tr[3], -1, 0, -1, 0);
- }
- }
-
-
- //• basePixMap - Handle to the PixMap to base GDevice on.
- //• *retGDevice - Returns a handle to the new GDevice.
- CreateGDevice (PixMapHandle basePixMap, GDHandle *retGDevice)
- {
- GDHandle newDevice; //• Handle to the new GDevice.
- ITabHandle embryoITab; //• Handle to the embryonic inverse table.
- Rect deviceRect; //• Rectangle of GDevice.
- OSErr error; //• Error code.
-
- //• Initialize a few things before we begin.
- error = noErr;
- newDevice = nil;
- embryoITab = nil;
-
- //• Allocate memory for the new GDevice.
- newDevice = (GDHandle)NewHandle (sizeof (GDevice));
- if (newDevice != nil)
- {
- //• Allocate the embryonic inverse table.
- embryoITab = (ITabHandle)NewHandleClear (2);
- if (embryoITab != nil)
- {
- //• Set rectangle of device to PixMap bounds.
- deviceRect = (**basePixMap).bounds;
-
- //• Initialize the new GDevice fields.
- (**newDevice).gdRefNum = 0; //• Only used for screens.
- (**newDevice).gdID = 0; //• Won’t normally use.
- if ((**basePixMap).pixelSize <= 8)
- (**newDevice).gdType = clutType; //• Depth≤8; clut device.
- else
- (**newDevice).gdType = directType; //• Depth>8; direct device.
- (**newDevice).gdITable = embryoITab; //• 2-byte handle for now.
- (**newDevice).gdResPref = kITabRes; //• Normal inv table res.
- (**newDevice).gdSearchProc = nil; //• No color-search proc.
- (**newDevice).gdCompProc = nil; //• No complement proc.
- (**newDevice).gdFlags = 0; //• Will set these later.
- (**newDevice).gdPMap = basePixMap; //• Reference our PixMap.
- (**newDevice).gdRefCon = 0; //• Won’t normally use.
- (**newDevice).gdNextGD = nil; //• Not in GDevice list.
- (**newDevice).gdRect = deviceRect; //• Use PixMap dimensions.
- (**newDevice).gdMode = -1; //• For nonscreens.
- (**newDevice).gdCCBytes = 0; //• Only used for screens.
- (**newDevice).gdCCDepth = 0; //• Only used for screens.
- (**newDevice).gdCCXData = 0; //• Only used for screens.
- (**newDevice).gdCCXMask = 0; //• Only used for screens.
- (**newDevice).gdReserved = 0; //• Currently unused.
-
- //• Set color-device bit if PixMap isn’t black & white.
- if ((**basePixMap).pixelSize > 1)
- SetDeviceAttribute (newDevice, gdDevType, true);
-
- //• Set bit to indicate that the GDevice has no video driver.
- SetDeviceAttribute (newDevice, noDriver, true);
-
- //• Initialize the inverse table.
- if ((**basePixMap).pixelSize <= 8)
- {
- MakeITable ((**basePixMap).pmTable, (**newDevice).gdITable,
- (**newDevice).gdResPref);
- error = QDError ();
- }
- }
- else
- error = MemError ();
- }
- else
- error = MemError ();
-
- //• Handle any errors along the way.
- if (error != noErr)
- {
- if (embryoITab != nil)
- DisposHandle ((Handle)embryoITab);
- if (newDevice != nil)
- DisposHandle ((Handle)newDevice);
- }
- else
- *retGDevice = newDevice;
-
- //• Return a handle to the new GDevice.
- return error;
- }
-
- //• DisposeOffScreen takes a CGrafPtr and disposes of it. It normally takes
- //• a CGrafPtr, but you can also use it to dispose of a regular GrafPtr by
- //• using a (CGrafPtr) typecast. Example call:
- //• DisposeOffScreen ((CGrafPtr)myGrafPtr);
-
- void DisposeOffScreen (
- CGrafPtr doomedPort) //• Pointer to the CGrafPort to be disposed of.
- {
- CGrafPtr currPort; //• Pointer to the current port.
-
- //• Check to see whether the doomed CGrafPort is the current port.
- GetPort ((GrafPtr *)&currPort);
- if (currPort == doomedPort)
- {
- //• It is; set current port to Window Manager CGrafPort.
- GetCWMgrPort (&currPort);
- SetPort ((GrafPtr)currPort);
- }
-
- //• Throw everything away.
- DisposPtr ((**doomedPort->portPixMap).baseAddr);
- if ((**doomedPort->portPixMap).pmTable != nil)
- DisposCTable ((**doomedPort->portPixMap).pmTable);
- CloseCPort (doomedPort);
- DisposPtr ((Ptr)doomedPort);
- }
-
-